/**
 * 
 */
package neptune.web.client.view.components.editor;

import gwt.canvas.client.Canvas;

import java.util.ArrayList;

import com.allen_sauer.gwt.dnd.client.DragContext;
import com.allen_sauer.gwt.dnd.client.PickupDragController;
import com.allen_sauer.gwt.dnd.client.drop.BoundaryDropController;
import com.google.gwt.user.client.ui.AbsolutePanel;
import com.google.gwt.user.client.ui.Widget;

/**
 * @author Roberto Bifulco [RobertoBifulco.it] [info@robertoBifulco.it]
 * 
 */
public class GraphicPanel extends AbsolutePanel {

	private Canvas canvas;
	private ArrayList<GraphicConnection> connections = new ArrayList<GraphicConnection>(
			0);
	private ArrayList<Widget> widgets = new ArrayList<Widget>(0);
	private PickupDragController dragController;
	private boolean activeDrag;

	public GraphicPanel(int width, int height) {
		this(width, height, false);
	}

	public GraphicPanel(int width, int height, boolean activeDrag) {
		super();
		this.activeDrag = activeDrag;
		setSize(width + "px", height + "px");
		canvas = new Canvas();
		canvas.setSize(width + "px", height + "px");
		add(canvas, 0, 0);

		if (activeDrag) {
			dragController = new PickupDragController(this, true) {
				public BoundaryDropController newBoundaryDropController(
						AbsolutePanel boundaryPanel, boolean allowDropping) {
					return new BoundaryDropController(boundaryPanel,
							allowDropping) {
						public void onMove(DragContext context) {
							super.onMove(context);
							GraphicPanel.this.redrawDraggable();
						}
					};
				}
			};

			// Positioner is always constrained to the boundary panel
			// Use 'true' to also constrain the draggable or drag proxy to the
			// boundary panel
			dragController.setBehaviorConstrainedToBoundaryPanel(true);
			// Allow multiple widgets to be selected at once using CTRL-click
			dragController.setBehaviorMultipleSelection(true);
		}
	}

	public void addConnection(Widget w1, Widget w2) {
		GraphicConnection conn = new GraphicConnection(w1, w2);
		connections.add(conn);
	}

	public void removeConnection(Widget w1, Widget w2) {
		for (GraphicConnection connection : connections) {
			if ((connection.getW1().equals(w1) && connection.getW2().equals(w2))
					|| (connection.getW1().equals(w2) && connection.getW2()
							.equals(w1))) {
				connections.remove(connection);
				break;
			}
		}
	}

	public void removeAllConnections() {
		connections.clear();
	}

	public void removeConnectionsWithEndPoint(Widget endPoint) {
		for (GraphicConnection connection : connections) {
			if ((connection.getW1().equals(endPoint) || connection.getW2()
					.equals(endPoint))) {
				connections.remove(connection);
				break;
			}
		}
	}

	public void drawNotDraggableConnection(Widget w1, Widget w2) {
		int x1, y1;
		x1 = getWidgetLeft(w1) + w1.getOffsetWidth() / 2;
		y1 = getWidgetTop(w1) + w1.getOffsetHeight() / 2;

		int x2, y2;
		x2 = getWidgetLeft(w2) + w2.getOffsetWidth() / 2;
		y2 = getWidgetTop(w2) + w2.getOffsetHeight() / 2;

		canvas.beginPath();
		canvas.moveTo(x1, y1);
		canvas.lineTo(x2, y2);
		canvas.closePath();
		canvas.stroke();
	}

	public void drawDraggableConnection(Widget w1, Widget w2) {
		if (!w1.isAttached() || !w2.isAttached()) {
			removeConnection(w1, w2);
			return;
		}

		int x1, y1;
		x1 = w1.getAbsoluteLeft() - getAbsoluteLeft() + w1.getOffsetWidth() / 2;
		y1 = w1.getAbsoluteTop() - getAbsoluteTop() + w1.getOffsetHeight() / 2;

		int x2, y2;
		x2 = w2.getAbsoluteLeft() - getAbsoluteLeft() + w2.getOffsetWidth() / 2;
		y2 = w2.getAbsoluteTop() - getAbsoluteTop() + w2.getOffsetHeight() / 2;

		canvas.beginPath();
		canvas.moveTo(x1, y1);
		canvas.lineTo(x2, y2);
		canvas.closePath();
		canvas.stroke();
	}

	public void redrawNotDraggable() {
		canvas.clear();
		for (GraphicConnection connection : connections) {
			drawNotDraggableConnection(connection.getW1(), connection.getW2());
		}
	}

	public void redrawDraggable() {
		canvas.clear();
		for (GraphicConnection connection : connections) {
			drawDraggableConnection(connection.getW1(), connection.getW2());
		}
	}

	public void makeDraggable(Widget w) {
		if (activeDrag)
			dragController.makeDraggable(w);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.google.gwt.user.client.ui.Panel#clear()
	 */
	@Override
	public void clear() {
		for (int i = 0; i < getWidgetCount(); i++) {
			if (!getWidget(i).equals(canvas))
				getWidget(i).removeFromParent();
		}
		canvas.clear();
	}

	public void clearPaints() {
		canvas.clear();
		for (Widget w : widgets) {
			w.removeFromParent();
		}
		widgets.clear();
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * com.google.gwt.user.client.ui.AbsolutePanel#add(com.google.gwt.user.client
	 * .ui.Widget, int, int)
	 */
	@Override
	public void add(Widget w, int left, int top) {
		super.add(w, left, top);
		if (!w.equals(canvas))
			widgets.add(w);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * com.google.gwt.user.client.ui.AbsolutePanel#add(com.google.gwt.user.client
	 * .ui.Widget)
	 */
	@Override
	public void add(Widget w) {
		super.add(w);
		if (!w.equals(canvas))
			widgets.add(w);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.google.gwt.user.client.ui.ComplexPanel#getWidget(int)
	 */
	@Override
	public Widget getWidget(int index) {
		return widgets.get(index);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.google.gwt.user.client.ui.ComplexPanel#getWidgetCount()
	 */
	@Override
	public int getWidgetCount() {
		return widgets.size();
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * com.google.gwt.user.client.ui.ComplexPanel#getWidgetIndex(com.google.
	 * gwt.user.client.ui.Widget)
	 */
	@Override
	public int getWidgetIndex(Widget child) {
		return widgets.indexOf(child);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * com.google.gwt.user.client.ui.AbsolutePanel#remove(com.google.gwt.user
	 * .client.ui.Widget)
	 */
	// @Override
	// public boolean remove(Widget w) {
	// widgets.remove(w);
	// return super.remove(w);
	// }

}
